Lua/Raw Hook Operations
=Introduction= CHDK 1.4 adds the ability to read and manipulate the raw image data inside the raw script hook, before the CHDK raw and camera jpeg are saved. This can be used to calculate subsequent exposure or modify the image. A flexible alternative to the shot_histogram function is included. Development thread http://chdk.setepontos.com/index.php?topic=11081.msg119265#msg119265 =General usage= The core functions are provided in a library called rawop, which is available by default. Some auxiliary functions are provide in the lua module rawoplib. To use rawop, you must * Ensure the camera is in a shooting mode with raw data available (get_raw_support() true) * Set the raw hook, with a timeout sufficient for all the operations you want to perform * Start a shot using scripted key presses (not using the shoot() function) * Wait for the raw hook to become ready * Analyze and/or modify the raw data using the rawop functions * Call hook_raw.continue() to allow the shooting process to continue Functions which access raw data are only valid inside the raw hook. If called when the raw hook is not active, they throw an error. These functions will also throw an error if valid raw data is known to be unavailable in the current shooting mode. =Functions for querying raw buffer characteristics= These functions may be called at any time, but some depend on values that can change between shots (currently on G1X only) so in general, it is recommended that they be called inside the hook. In future versions, more values may change at runtime. rawop.get_cfa cfa=rawop.get_cfa() cfa: CFA pattern as a 32 bit interger, as used in DNG rawop.get_cfa_offsets cfa_offsets=rawop.get_cfa_offsets() cfa_offsets: offsets of color filter elements with respect to an even valued x,y pair, in the form { r={ y=1, x=0, }, g1={ y=0, x=0, }, b={ y=0, x=1, }, g2={ y=1, x=1, }, } rawop.get_bits_per_pixel bpp=rawop.get_bits_per_pixel() bpp: sensor bit depth. 10, 12, or 14 in currently supported cameras rawop.get_raw_neutral neutral=rawop.get_raw_neutral() neutral: approximate raw value of a neutral grey target exposed with Canon AE. This is designed such that raw values can be expressed as an Ev offset from "correct" exposure, so raw_to_ev(neutral) = 0 This is not aware of CFA, it is based on an average of all color elements NOTE on G1x, the value may change depending on ISO settings. The value is only updated when the raw hook is entered for the shot so for maximum portability, this function should only be called inside the raw hook. rawop.get_black_level blacklevel=rawop.get_black_level() blacklevel: sensor black level value. This is theoretically the value of a pixels which has received no detectable light. However un-exposed pixels may have higher values due to sensor effects (hot pixels, dark current etc) and can also have lower values in some cases. NOTE on G1x, the value may change depending on ISO settings. The value is only updated when the raw hook is entered for the shot so for maximum portability, this function should only be called inside the raw hook. rawop.get_white_level whitelevel=rawop.get_white_level() whitelevel: sensor white level value (currently 2^bpp - 1 for all known sensors), the maximum value a pixel can have. =Functions for querying raw dimensions= The values returned by these functions do not currently change at runtime, but it is possible they could change with shooting mode in future versions. Active area generally includes all of the sensor area known to contain image data. This often includes dark borders of pixels which contain recognizable image data that is not exposed the same as the majority of the sensor. JPEG area may be a better choice for whole scene measurements. Active area coordinates in CHDK are guaranteed to be even. If the sensor active area physically occupies odd values, they will be excluded. JPEG area represents the approximate area of the sensor used for the JPEG, but may not exactly match either the pixel dimensions or sensor area. JPEG area generally will not include the dark borders that can affect active area, so jpeg area is a good choice for measuring the whole scene. These JPEG area functions return sensor coordinates, unlike the DNG specification which gives default crop in terms of active area. Both active area and JPEG area are defined in the port, and are not affected by the "Crop size" DNG menu option. rawop.get_raw_width width=rawop.get_raw_width() width: The width of the sensor in pixels. rawop.get_raw_height height=rawop.get_raw_height() height: The height of the sensor in pixels. rawop.get_active_left left=rawop.get_active_left() left: X coordinate of the leftmost pixel in the active area rawop.get_active_top top=rawop.get_active_top() top: y coordinate of the topmost pixel in the active area rawop.get_active_width width=rawop.get_active_width() width: width of the active area, in pixels rawop.get_active_height height=rawop.get_active_height() height: height of the active area, in pixels rawop.get_jpeg_left left=rawop.get_jpeg_left() left: X coordinate of the leftmost pixel in the jpeg area rawop.get_jpeg_top top=rawop.get_jpeg_top() top: y coordinate of the topmost pixel in the jpeg area rawop.get_jpeg_width width=rawop.get_jpeg_width() width: width of the jpeg area, in pixels rawop.get_jpeg_height height=rawop.get_jpeg_height() height: height of the jpeg area, in pixels =Functions for querying and modifying raw data= An error is generated if the these functions are called outside the raw hook, or in a shooting mode for which raw data is not available. Functions with rgbg in the name operate on "quads" of pixels. Coordinates are truncated to even values, so the function will operate on the quad containing the specified coordinates. When rgbg values are specified, the second G will default to the value of the first if not given. rawop.get_pixel v=rawop.get_pixel(x,y) v: raw value, or nil if out of bounds rawop.set_pixel rawop.set_pixel(x,y,v) Sets pixel at x,y to value v. If x or y fall outside the sensor area, the call is ignored. If the v is larger than allowed by the camera bit depth, the behavior is unspecified. rawop.get_pixels_rgbg r,g1,b,g2=rawop.get_pixels_rgbg(x,y) r,g1,b,g2: Red, green, blue and green values of the quad containing x,y, or nil if out of bounds. rawop.set_pixels_rgbg rawop.set_pixels_rgbg(x,y,r,g1,b,g2) Sets the values of the CFA quad containing x,y. If g2 is not specified, it is set to g1. If x or y fall outside the sensor area, the call is ignored. If the color valuers are larger than allowed by the camera bit depth, the behavior is unspecified. rawop.fill_rect rawop.fill_rect(x,y,width,height,val[,xstep,ystep]) Sets every step-th pixel of the specified rectangle to the specified value. Width and height out of bounds are clipped. xstep defaults to 1, ystep defaults to xstep Step 2 can be used with CFA offsets to fill RGB (see rawoplib fill_rect_rgbg) This function can take a substantial amount of time when large areas are set (TODO example) rawop.meter mean_raw_val=rawop.meter(x,y,x_count,y_count,x_step,y_step) mean_raw_val: average values of count pixels in x and y, sampled at step size step, or nil if the range is invalid or the total number of pixels could result in overflow To prevent overflow, the total number of pixels must less unsigned_max / white_level. Limits are roughly 10 bpp = 4 Mpix 12 bpp = 1 Mpix 14 bpp = 256 Kpix To meter larger numbers of pixels, use multiple calls and average the results To meter R G B separately, use multiple meter calls with the appropriate CFA offset and even steps (see rawoplib meter_rgb and meter_rgbg) To ensure all CFA colors are sampled in a single call, use odd step values. This function can take a substantial amount of time when large counts are used (TODO example) =Functions for converting raw values for exposure calculation= rawop.raw_to_ev ev=rawop.raw_to_ev(rawval,scale) ev: APEX-like "Ev" of the raw value, such that raw_to_ev(raw_neutral) 0, and N*scale is N "stops" above or below neutral. If rawval is <= to blacklevel, it is clamped to blacklevel + 1. rawval > whitelevel is converted without any special treatment. scale is optionally scales the APEX value. The default is 96, which results in values that can be used directly in calculations with the cameras normal APEX*96 exposure values. Use 1000 for imath APEX values or 96000 for APEX96 with imath. NOTE on G1x, the result may change depending on ISO settings. The value is only updated when the raw hook is entered for the shot so for maximum portability, this function should only be called inside the raw hook. rawop.ev_to_raw rawval=rawop.ev_to_raw(ev,scale) Convert an APEX-like "Ev" value as described above into a raw value. No range checking is done. scale optionally specifies a scale factor to divide the Ev value by before conversion. The default is 96 to be compatible with camera exposure parameters and raw_to_ev defaults. NOTE on G1x, the result may change depending on ISO settings. The value is only updated when the raw hook is entered for the shot so for maximum portability, this function should only be called inside the raw hook. =Histogram functions= rawop provides flexible raw histogram functions through histogram objects. Multiple histograms can be created, and used to sample specified regions of the raw buffer. Except for rawop.create_histogram, all histogram functions are provided by the object. These are referred to with the notation histo:'function_name' below, but the actual name will be the variable you assigned the histogram object to. Histograms data is built by calling histo:update(). Querying a histogram with no data generates an error. rawop.create_histogram histo=rawop.create_historam() histo: A new histogram object. histo:update histo:update(top,left,width,height,xstep,ystep,bits) Update histogram data using specified area of raw buffer. Bits specifies the bit depth of histogram. Defaults to camera bit depth, and must be <= camera bit depth. The amount of memory required for the histogram data is determined by bits. An error is generated if the called outside the raw hook, or in a shooting mode for which raw data is not available. To generate color specific histograms, use CFA offsets and even steps. To generate a histogram including all CFA channels, use odd steps. This function may take a substantial amount of time when used on large numbers of pixels (TODO example) Memory is allocated for the histogram data on the first update call, and re-allocated if bit depth changes. It is freed either by normal Lua garbage collection or an explicit call to histo:free() histo:range frac=histo:range(min,maxscale) frac: number of values in range, either as a fraction in parts per scale, or total count. min, max: range of values to query, in raw values scaled to the bit depth specified in histo:update(). An error is generated if min > max or either falls outside the range of valid values for the histogram bit depth. scale: defaults to 100, use the string 'count' for raw counts. When large number of pixels are involved, calculations involving raw counts or very large scales can may result in overflow. An error is generated if the histogram does not contain data. This function may take a non-trivial amount of time to execute. histo:total_pixels total=histo:total_pixels() total: The total number of pixels sampled by the histogram. An error is generated if the histogram does not contain data. histo:bits bits=histo:bits() bits: The bit depth specified in the last call to histo:update(). An error is generated if the histogram does not contain data. histo:free histo:free() Immediately free memory used by histogram data. histo:update must be called again to before any other functions. If histo:free() is not called, memory associated with the histogram will be freed along with the histogram object following normal Lua garbage collection rules. =rawoplib Lua module= The rawoplib module adds some additional convenence functions to rawop. To use it, just add require'rawoplib' to your script. The functions are added to the existing rawop table. rawop.fill_rect_rgbg rawop.fill_rect_rgbg(x,y,width,height,r,g1,b,g2) Fill the specified rectangle with the given color values. rawop.rect_rgbg rawop.rect_rgbg(x,y,width,height,linewidth,r,g1,b,g2) Draw an hollow rectangle with the given colors and line width. rawop.rect rawop.rect(x,y,width,height,linewidth,v,xstep,ystep) Draw a hollow rectangle with a single color value rawop.meter_rgbg r,g1,b,g2=rawop.meter_rgbg(x,y,xcount,ycount,xstep,ystep) Return the average value of pixels the each color channel in the specified area. Uses one rawop.meter call for each channel, using cfa offsets and the provided count and step values. xstep and ystep must be even. count and step values are subject to the same limits as rawop.meter() rawop.meter_rgb r,g1,b=rawop.meter_rgbg(x,y,xcount,ycount,xstep,ystep) Like rawop.meter_rgbg, but only measures the "first" green channel. =Performance notes= TODO =Examples= See CHDK/SCRIPTS/TEST/DRTEST.LUA and CHDK/SCRIPTS/TEST/RAWDRAW.LUA for some examples. TODO some simple code samples =Known issues= TODO Category:Lua Category:Scripting